package com.jddup.program.dao.handler.impl;

import com.jddup.common.exception.JddupException;
import com.jddup.common.pojo.TableColumn;
import com.jddup.common.pojo.TableMeta;
import com.jddup.program.dao.handler.IUpdateHandler;
import com.jddup.program.dao.sqlbuilder.UpdatePrepareSQLBuilder;
import com.jddup.program.dao.statement.IUpdatePrepareStatementSetter;
import com.jddup.program.etm.EntityToTableMetaConvertor;

import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * Created by ZZB on 2017/10/19.
 */
public class UpdateHandlerImpl implements IUpdateHandler {
	private UpdatePrepareSQLBuilder updatePrepareSQLBuilder;
	private IUpdatePrepareStatementSetter updatePrepareStatementSetter;
	private EntityToTableMetaConvertor entityToTableMetaConvertor;

	public UpdateHandlerImpl(UpdatePrepareSQLBuilder updatePrepareSQLBuilder,
							 IUpdatePrepareStatementSetter updatePrepareStatementSetter,
							 EntityToTableMetaConvertor entityToTableMetaConvertor) {
		this.updatePrepareSQLBuilder = updatePrepareSQLBuilder;
		this.updatePrepareStatementSetter = updatePrepareStatementSetter;
		this.entityToTableMetaConvertor = entityToTableMetaConvertor;
	}

	@Override
	public int updateBySQL(String sql, Connection connection) {
		try {
			Statement statement = connection.createStatement();
			return statement.executeUpdate(sql);
		} catch (SQLException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int updateBySQL(String sql, Object[] objects, Connection connection) {
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(sql);
			for (int i = 0; i < objects.length; i++) {
				preparedStatement.setObject(i + 1, objects[i]);
			}
			return preparedStatement.executeUpdate();
		} catch (SQLException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int update(Object o, Connection connection) {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(o.getClass());
		String updateSQL = updatePrepareSQLBuilder.buildUpdateSQL(tableMeta);
		if (updateSQL == null) {
			return 0;
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			updatePrepareStatementSetter.setInPrepareStatement(preparedStatement, tableMeta, o);
			return preparedStatement.executeUpdate();
		} catch (SQLException | InvocationTargetException | NoSuchMethodException | IllegalAccessException
				| NoSuchFieldException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int update(Object o, String tableName, Connection connection) {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(o.getClass());
		tableMeta.setTableName(tableName);
		String updateSQL = updatePrepareSQLBuilder.buildUpdateSQL(tableMeta);
		if (updateSQL == null) {
			return 0;
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			updatePrepareStatementSetter.setInPrepareStatement(preparedStatement, tableMeta, o);
			return preparedStatement.executeUpdate();
		} catch (SQLException | InvocationTargetException | NoSuchMethodException | IllegalAccessException
				| NoSuchFieldException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int[] updateList(List<?> objects, Connection connection) throws JddupException {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(objects.get(0).getClass());
		String updateSQL = updatePrepareSQLBuilder.buildUpdateSQL(tableMeta);
		if (updateSQL == null) {
			return new int[] { 0 };
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			updatePrepareStatementSetter.setBatchInPrepareStatement(preparedStatement, tableMeta, objects);
			return preparedStatement.executeBatch();
		} catch (SQLException | NoSuchMethodException | IllegalAccessException | NoSuchFieldException
				| InvocationTargetException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int[] updateList(List<?> objects, String tableName, Connection connection) {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(objects.get(0).getClass());
		tableMeta.setTableName(tableName);
		String updateSQL = updatePrepareSQLBuilder.buildUpdateSQL(tableMeta);
		if (updateSQL == null) {
			return new int[] { 0 };
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			updatePrepareStatementSetter.setBatchInPrepareStatement(preparedStatement, tableMeta, objects);
			return preparedStatement.executeBatch();
		} catch (SQLException | NoSuchMethodException | IllegalAccessException | NoSuchFieldException
				| InvocationTargetException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int updateField(Object pk, Class<?> tClass, String updateField, Object value, Connection connection)
			throws JddupException {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(tClass);
		TableColumn tableColumn = entityToTableMetaConvertor.obtainByFieldName(tClass, updateField);
		if (tableColumn != null) {
			updateField = tableColumn.getColumnName();
		}
		String updateSQL = updatePrepareSQLBuilder.buildUpdateFieldSQL(tableMeta, updateField, value, pk);
		if (updateSQL == null) {
			return 0;
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			preparedStatement.setObject(1, value);
			preparedStatement.setObject(2, pk);
			return preparedStatement.executeUpdate();
		} catch (SQLException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int updateField(Object pk, String tableName, Class<?> tClass, String updateField, Object value,
			Connection connection) {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(tClass);
		tableMeta.setTableName(tableName);
		TableColumn tableColumn = entityToTableMetaConvertor.obtainByFieldName(tClass, updateField);
		if (tableColumn != null) {
			updateField = tableColumn.getColumnName();
		}
		String updateSQL = updatePrepareSQLBuilder.buildUpdateFieldSQL(tableMeta, updateField, value, pk);
		if (updateSQL == null) {
			return 0;
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			preparedStatement.setObject(1, value);
			preparedStatement.setObject(2, pk);
			return preparedStatement.executeUpdate();
		} catch (SQLException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int updateListField(List<?> pks, Class<?> tClass, String updateField, Object value, Connection connection)
			throws JddupException {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(tClass);
		TableColumn tableColumn = entityToTableMetaConvertor.obtainByFieldName(tClass, updateField);
		if (tableColumn != null) {
			updateField = tableColumn.getColumnName();
		}
		String updateSQL = updatePrepareSQLBuilder.buildUpdateListFieldSQL(tableMeta, updateField, value, pks);
		if (updateSQL == null) {
			return 0;
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			preparedStatement.setObject(1, value);
			for (int i = 0; i < pks.size(); i++) {
				preparedStatement.setObject(i + 2, pks.get(i));
			}
			return preparedStatement.executeUpdate();
		} catch (SQLException e) {
			throw new JddupException(e);
		}
	}

	@Override
	public int updateListField(List<?> pks, String tableName, Class<?> tClass, String updateField, Object value,
			Connection connection) {
		TableMeta tableMeta = entityToTableMetaConvertor.convertFromClass(tClass);
		tableMeta.setTableName(tableName);
		TableColumn tableColumn = entityToTableMetaConvertor.obtainByFieldName(tClass, updateField);
		if (tableColumn != null) {
			updateField = tableColumn.getColumnName();
		}
		String updateSQL = updatePrepareSQLBuilder.buildUpdateListFieldSQL(tableMeta, updateField, value, pks);
		if (updateSQL == null) {
			return 0;
		}
		try {
			PreparedStatement preparedStatement = connection.prepareStatement(updateSQL);
			preparedStatement.setObject(1, value);
			for (int i = 0; i < pks.size(); i++) {
				preparedStatement.setObject(i + 2, pks.get(i));
			}
			return preparedStatement.executeUpdate();
		} catch (SQLException e) {
			throw new JddupException(e);
		}
	}
}
